from asyncio import QueueEmpty
from socket import timeout
from time import sleep
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from queue import Queue
from es import Es

from widgetMessage import msgDialog
from queue import Queue
from comInterface import SerialPort, TcpClient
import serial.tools.list_ports
from config import config
import queue
from log import logger

comInterfaces = []

widgetHeight = 25

class SerialPortWidget(QWidget):

    def __init__(self, queueRecv:Queue=None):
        super().__init__()
        
        self.port = SerialPort("485")
        comInterfaces.append(self.port)

        self.layoutSerial = QGridLayout()
        self.comboCom = QComboBox()
        self.comboBaudRate = QComboBox()
        self.comboStopBit = QComboBox()
        self.comboParity = QComboBox()
        self.buttonScan = QPushButton("扫描可用串口")
        self.buttonOpen = QPushButton("打开串口")
        self.layoutSerial.addWidget(QLabel("串口号: "), 0,0,1,1)
        self.layoutSerial.addWidget(QLabel("波特率: "), 1,0,1,1)
        self.layoutSerial.addWidget(QLabel("校验位: "), 2,0,1,1)
        self.layoutSerial.addWidget(QLabel("停止位: "), 3,0,1,1)
        self.layoutSerial.addWidget(self.comboCom,      0, 1, 1, 3)
        self.layoutSerial.addWidget(self.comboBaudRate, 1, 1, 1, 3)
        self.layoutSerial.addWidget(self.comboParity,  2, 1, 1, 3)
        self.layoutSerial.addWidget(self.comboStopBit,  3, 1, 1, 3)
        self.layoutSerial.addWidget(self.buttonScan,  4, 0, 1, 4)
        self.layoutSerial.addWidget(self.buttonOpen,  5, 0, 1, 4)

        baudrates = [50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000, 3000000, 3500000, 4000000]
        for i in baudrates:
            self.comboBaudRate.addItem(str(i), i)
        self.comboBaudRate.setCurrentText("38400")
        self.comboParity.addItem("none", serial.PARITY_NONE)
        self.comboParity.addItem("odd", serial.PARITY_ODD)
        self.comboParity.addItem("even", serial.PARITY_EVEN)
        self.comboStopBit.addItem("1", serial.STOPBITS_ONE)
        self.comboStopBit.addItem("2", serial.STOPBITS_TWO)
        
        self.setLayout(self.layoutSerial)
        self.buttonScan.clicked.connect(self.scanCom)
        self.buttonOpen.clicked.connect(self.openCom)

        self.timerThreadChecker = QTimer()
        self.timerThreadChecker.timeout.connect(self.checkThread)
        self.timerThreadChecker.start(500)

        self.comboCom.setMinimumHeight(widgetHeight)
        self.comboBaudRate.setMinimumHeight(widgetHeight)
        self.comboParity.setMinimumHeight(widgetHeight)
        self.comboStopBit.setMinimumHeight(widgetHeight)
        self.buttonOpen.setMinimumHeight(widgetHeight)
        self.buttonScan.setMinimumHeight(widgetHeight)

        
        self.comboCom.setView(QListView())
        self.comboBaudRate.setView(QListView())
        self.comboParity.setView(QListView())
        self.comboStopBit.setView(QListView())

        self.buttonScan.clicked.emit()

    def scanCom(self):
        self.comboCom.clear()
        port_list = list(serial.tools.list_ports.comports())
        logger.info(port_list)
        for i in port_list:
            self.comboCom.addItem("[%s] %s" % (i.name ,i.description.split("(")[0]), i.name)
        self.comboCom.view().setFixedWidth(300)

    def openCom(self):
        if self.buttonOpen.text() == "打开串口":
            serialPara = {}

            serialPara["port"] = self.comboCom.currentData()
            serialPara["baudrate"] = self.comboBaudRate.currentData()
            serialPara["parity"] = self.comboParity.currentData()
            serialPara["stopbits"] = self.comboStopBit.currentData()
            
            result, errInfo = self.port.open(serialPara)

            if result == True:
                self.buttonOpen.setText("关闭串口")
                self.port.startRecvThread()
                # msgDialog("提示", "串口打开成功")
            else:
                msgDialog("提示", errInfo)
                return
        else:
            self.buttonOpen.setText("打开串口")
            self.port.release()
            # msgDialog("提示", "串口关闭成功")

    # 检查串口是否退出
    def checkThread(self):
        if self.port.isOpen() is True and self.port.isRecvThreadAlive() is False:
            msgDialog("错误", "串口因异常而关闭, 请重新打开")
            self.buttonOpen.setText("打开串口")
            self.threadRead = None
            self.port.release()


class TcpClientWidget(QWidget):

    def __init__(self, queueRecv:Queue=None, name:str="tcp"):
        super().__init__()
        
        regDevices = QRegExp()
        regDevices.setPattern("^([0-9]+-[0-9]+)|([0-9]+,?)+$")
        regValidatorDevice = QRegExpValidator(regDevices)
        regOnlyNumber = QRegExp()
        regOnlyNumber.setPattern("^([0-9])+$")
        self.regValidatorOnlyNumber = QRegExpValidator(regOnlyNumber)

        self.tcpClient = TcpClient("Tcp")
        comInterfaces.append(self.tcpClient)

        self.layoutSerial = QGridLayout()
        self.host = QLineEdit()
        self.host.setText(config["interface"]["tcp"]["server"])
        self.port = QLineEdit()
        self.port.setText(str(config["interface"]["tcp"]["port"]))
        self.port.setValidator(self.regValidatorOnlyNumber)
        self.buttonOpen = QPushButton("连接")
        self.layoutSerial.addWidget(QLabel("IP: "), 0,0,1,1)
        self.layoutSerial.addWidget(QLabel("端口: "), 1,0,1,1)
        self.layoutSerial.addWidget(self.host, 0, 1, 1, 3)
        self.layoutSerial.addWidget(self.port, 1, 1, 1, 3)
        self.layoutSerial.addWidget(self.buttonOpen,  2, 0, 1, 4)
        
        self.setLayout(self.layoutSerial)
        self.buttonOpen.clicked.connect(self.openCom)

        self.timerThreadChecker = QTimer()
        self.timerThreadChecker.timeout.connect(self.checkThread)
        self.timerThreadChecker.start(500)

        self.host.setMinimumHeight(widgetHeight)
        self.port.setMinimumHeight(widgetHeight)
        self.buttonOpen.setMinimumHeight(widgetHeight)

    def openCom(self):
        
        if self.buttonOpen.text() == "连接":
            socketPara = {}

            if self.host.text() == "" or self.port.text() == "":
                msgDialog("提示", "ip与端口不能为空")
                return

            socketPara["host"] = self.host.text()
            socketPara["port"] = self.port.text()
            
            result, errInfo = self.tcpClient.open(socketPara)

            if result == True:
                self.buttonOpen.setText("断开")
                self.tcpClient.startRecvThread()
                # msgDialog("提示", "连接成功")
            else:
                msgDialog("提示", errInfo)
                return
        else:
            self.buttonOpen.setText("连接")
            self.tcpClient.release()
            # msgDialog("提示", "断开成功")

    # 检查串口是否退出
    def checkThread(self):
        if self.tcpClient.isOpen() is True and self.tcpClient.isRecvThreadAlive() is False:
            msgDialog("错误", "链接因异常而关闭, 请重新打开")
            self.buttonOpen.setText("连接")
            self.tcpClient.release()

class ComInterfaceWidget(QComboBox):
    def __init__(self):
        super().__init__()
        
        listView = QListView()
        self.setView(listView)
        for interface in comInterfaces:
            self.addItem(interface.tag(), interface)

        self.protocolList = {}

    def currentInterface(self):
        return self.currentData()